<!DOCTYPE html>
<html>
  <head>
    <title>
      Test premature GC upon OscillatorNode and AudioBufferSourceNode
    </title>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script src="../resources/audit-util.js"></script>
    <script src="../resources/audit.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      let sampleRate = 44100;
      let renderDuration = 1;

      let audit = Audit.createTaskRunner();


      // Create a graph for testing in an isolated scope. Returns |context|.
      // Create two nodes and schedule only one of them. Then check if |onended|
      // from the scheduled node is fired correctly.
      function createGraphInIsolatedScope(sourceNodeType, task, should) {
        'use strict';

        let context =
            new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);

        {
          let node = context['create' + sourceNodeType]();
          node.connect(context.destination);

          if (sourceNodeType === 'BufferSource') {
            let emptyBuffer = context.createBuffer(1, sampleRate, sampleRate);
            node.buffer = emptyBuffer;
          }

          // If the node is GCed, |onended| won't be fired. Then this test
          // will be timed out because done() will not get called.
          node.onended = function() {
            should(
                true,
                sourceNodeType + 'Node 1 survived GC and onended event fired')
                .beEqualTo(true);
            task.done();
          };

          node.start();
          node.stop(0.5 * renderDuration);
        }

        // Suspend and GC before the render finishes. The time position is
        // arbitrary. GC should collect |osc2| because it is not scheduled.
        context.suspend(0.1 * renderDuration).then(function() {
          gc();
          context.resume();
        });

        context.startRendering();
      }

      audit.define('oscillator-onended', (task, should) => {
        createGraphInIsolatedScope('Oscillator', task, should);
      });

      audit.define('buffersource-onended', (task, should) => {
        createGraphInIsolatedScope('BufferSource', task, should);
      });

      audit.run();
    </script>
  </body>
</html>
